using System;
using System.Collections.Concurrent;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;

using Sustainalytics.Utils.Configuration;

namespace Sustainalytics.ReportGenerator.BL
{
    using System.Configuration;

    using Sustainalytics.Entities;

    public class PdfEmailLogger : ILogPdf
    {
        private ConcurrentQueue<string> _queueLog;
        private ConcurrentQueue<string> _summaryQueueLog;

        public PdfEmailLogger()
        {
            _queueLog = new ConcurrentQueue<string>();
            _summaryQueueLog = new ConcurrentQueue<string>();
        }

        public void LogError(string error)
        {
            SendLogByEmail(error, true);
        }

        public void LogSuccess(string message)
        {
            LogInfo("Succeded");
        }

        public void LogGenerationData(string msg)
        {
            _queueLog.Enqueue(string.Format("{0}", msg));
        }

        public void LogSummary(string msg)
        {
            _summaryQueueLog.Enqueue(string.Format("{0}", msg));
        }

        public void LogInfo(string subject)
        {
            SendLogByEmail(subject, false);
        }

        private void SendLogByEmail(string message, bool isError)
        {
            var deploymentLocation = ConfigurationManager.AppSettings["DeploymentLocation"];
            var subjStart = SettingsHelper.Read("SynchronizationName", "GA Pdf Generation");
            var machineName = deploymentLocation == DeploymentLocation.Development.ToString()
                                  ? Environment.MachineName.ToUpperInvariant()
                                  : deploymentLocation;
            var subject = string.Format("{0} {1} {2}", subjStart, machineName, isError ? "ERROR" : message);
            var support = SettingsHelper.Read("SupportEmail", "platformsupport@sustainalytics.com");

            var maxMessages = SettingsHelper.Read("MaxEmailBodyMessages", 1000);
                        
            var bodyContent = new StringBuilder();
            bodyContent.AppendLine("Summary Log");
            _summaryQueueLog.ToList().ForEach(x => bodyContent.AppendLine(x));            
            if (isError)
                bodyContent.AppendLine(message);
            else if (_summaryQueueLog.Any() == false)
                bodyContent.AppendLine("No summary to display.");
            
            bodyContent.AppendLine("");
            bodyContent.AppendLine("Detailed Log");

            var sbDetails = new StringBuilder();
            _queueLog.ToList().ForEach(x => sbDetails.AppendLine(x));
            if (isError)
                sbDetails.AppendLine(message);
            else if (_queueLog.Any() == false)
                bodyContent.AppendLine("No details to display.");

            if (_queueLog.Count() > maxMessages)
            {
                bodyContent.AppendLine("Due to large amount of data, details can be found in the attachment.");
                SendEmail(new[] { support }, null, subject, bodyContent.ToString(), false, true, "logs.txt", Encoding.ASCII.GetBytes(sbDetails.ToString()));
            }
            else
            {
                bodyContent.Append(sbDetails.ToString());
                SendEmail(new[] { support }, null, subject, bodyContent.ToString(), false, false, string.Empty, new byte[0]);
            }
                        
            if (!isError)
            {
                _queueLog = new ConcurrentQueue<string>();
                _summaryQueueLog = new ConcurrentQueue<string>();
            }
        }

        public void SendEmailLog(string subject)
        {
            var support = SettingsHelper.Read("SupportEmail", "platformsupport@sustainalytics.com");
            var sb = new StringBuilder();
            foreach (var data in this._queueLog)
            {
                sb.AppendLine(data);
            }
            SendEmail(new[] { support }, null, subject, sb.ToString(), false, false, "", new byte[0]);
        }

        private static void SendEmail(
            string[] recipients, 
            string[] replyTo, 
            string subject, 
            string body, 
            bool isBodyHtml, 
            bool hasAttachment, 
            string attachmentName, 
            byte[] attachmentContent)
        {
            if (subject == null || body == null)
            {
                return;
            }

            var mail = new MailMessage();

            var from = SettingsHelper.Read("SMTPUserName", "platform@sustainalytics.com");

            mail.From = new MailAddress(from);
            mail.Subject = subject;
            mail.Body = body;
            mail.IsBodyHtml = isBodyHtml;
            var attachmentArchivingThresholdKb = int.Parse(SettingsHelper.Read("AttachmentArchivingThresholdKB", "500"));

            if (recipients != null && recipients.Any())
            {
                mail.To.Clear();

                for (var i = 0; i < recipients.Count(); i++)
                {
                    mail.To.Add(new MailAddress(recipients.ElementAt(i)));
                }
            }

            if (replyTo != null && replyTo.Any())
            {
                mail.CC.Clear();

                for (var i = 0; i < replyTo.Count(); i++)
                {
                    mail.CC.Add(new MailAddress(replyTo.ElementAt(i)));
                }
            }

            if (hasAttachment)
            {
                var contentType = new ContentType
                                      {
                                          Name = attachmentName, 
                                          MediaType = MediaTypeNames.Application.Octet
                                      };

                if (attachmentContent.Length > attachmentArchivingThresholdKb * 1024)
                {
                    // compress attachments larger than the set archiving threshold
                    var archivingFolder = Directory.CreateDirectory("ArchivingDir");

                    File.WriteAllBytes(Path.Combine(archivingFolder.Name, contentType.Name), attachmentContent);
                    contentType.Name += ".zip";

                    ZipFile.CreateFromDirectory(archivingFolder.Name, contentType.Name);

                    // GZipStream/DeflateStream does not provide a way to include a file name in the header of the zipped stream
                    attachmentContent = File.ReadAllBytes(contentType.Name);
                    archivingFolder.Delete(true);
                    File.Delete(contentType.Name);
                }

                mail.Attachments.Add(new Attachment(new MemoryStream(attachmentContent), contentType));
            }

            using (
                var smtpClient = new SmtpClient(SettingsHelper.Read("SMTPServer", "smtp.office365.com"))
                                     {
                                         Port = int.Parse(SettingsHelper.Read("SMTPServerPort", "587")),
                                         Credentials = new NetworkCredential(SettingsHelper.Read("SMTPUserName", "platform@sustainalytics.com"), SettingsHelper.Read("SMTPPassword", "Password99#")),
                                         EnableSsl = true
                                     })
            {
                smtpClient.Send(mail);
            }
        }
    }
}